﻿using System;
using System.Runtime.InteropServices;
using System.Drawing;

using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Structure;

namespace CellImageProcessing
{
    public class ImageProcessing
    {
        #region DLL Import
        [DllImport(@"ImageProcessing.dll", EntryPoint = "Convert2Grayscale")]
        private static extern IntPtr __Convert2Grayscale(IntPtr inputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "InvertImage")]
        private static extern IntPtr __InvertImage(IntPtr inputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "BinarizeImage")]
        private static extern IntPtr __BinarizeImage(IntPtr inputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "ErodeImage")]
        private static extern IntPtr __ErodeImage(IntPtr inputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "SobelFilter")]
        private static extern void __SobelFilter(IntPtr inputImage, IntPtr outputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "ResizeWithRate")]
        private static extern IntPtr __ResizeWithRate(IntPtr inputImage, double rate);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "Resize")]
        private static extern IntPtr __Resize(IntPtr inputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "EraseBackgroundWithThreshold1")]
        private static extern void __EraseBackgroundWithThreshold1(IntPtr inputImage, IntPtr outputImage, int Threshold);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "EraseBackgroundWithThreshold2")]
        private static extern void __EraseBackgroundWithThreshold2(IntPtr inputImage, IntPtr outputImage, int backGray, int diffThres);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "EraseBackground")]
        private static extern void __EraseBackground(IntPtr inputImage, IntPtr outputImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "RemoveGrid")]
        private static extern void __RemoveGrid(IntPtr inputImage, IntPtr outputImage, IntPtr gridImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "GetGrid")]
        private static extern void __GetGrid(IntPtr inputImage, IntPtr outputImage, double angle);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "BlurGrid")]
        private static extern void __BlurGrid(IntPtr inputImage, IntPtr outputImage, IntPtr gridImage);
        [DllImport(@"ImageProcessing.dll", EntryPoint = "ContrastStretch")]
        private static extern void __ContrastStretch(IntPtr inputImage, IntPtr outputImage);
        #endregion

        #region Methods
        /// <summary>
        /// Crop the image with the given region
        /// </summary>
        /// <param name="inputImage">The original input image</param>
        /// <param name="croppedRegion">The cropped region of the input image.</param>
        /// <returns>Cropped image</returns>
        public static Image<Bgr, Byte> Cropping(Image<Bgr, Byte> inputImage, Rectangle croppedRegion)
        {
            return inputImage.Copy(croppedRegion);
        }

        public static Image<Gray, Byte> Cropping(Image<Gray, Byte> inputImage, Rectangle croppedRegion)
        {
            return inputImage.Copy(croppedRegion);
        }

        /// <summary>
        /// Convert the color image to grayscale.
        /// </summary>
        /// <param name="inputImage">The original input image</param>
        /// <returns>The grayscale image</returns>
        public static Image<Gray, Byte> Convert2Grayscale(Image<Bgr, Byte> inputImage)
        {
            return inputImage.Convert<Gray, Byte>();
        }

        //private static Image<Gray, Byte> Convert2Grayscale(Image<Bgr, Byte> inputImage)
        //{
        //    IntPtr resultPtr = __Convert2Grayscale(inputImage.Ptr);

        //    Image<Gray, Byte> result = new Image<Gray, Byte>(inputImage.Width, inputImage.Height);
        //    result.Ptr = resultPtr;

        //    return result;
        //}

        public static Image<Bgr, Byte> InvertImage(Image<Bgr, Byte> inputImage)
        {
            return inputImage.Not();
        }

        public static Image<Gray, Byte> InvertImage(Image<Gray, Byte> inputImage)
        {
            return inputImage.Not();
        }

        //private static Image<Gray, Byte> InvertImage(Image<Gray, Byte> inputImage)
        //{
        //    IntPtr resultPtr = __InvertImage(inputImage.Ptr);

        //    Image<Gray, Byte> result = new Image<Gray, Byte>(inputImage.Width, inputImage.Height);
        //    result.Ptr = resultPtr;

        //    return result;
        //}

        public static void ConstrastStretch(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage)
        {
            __ContrastStretch(inputImage.Ptr, outputImage.Ptr);
        }

        /// <summary>
        /// Binarize the image
        /// </summary>
        /// <param name="inputImage">The original input image</param>
        /// <param name="maxintensity">The maximum intensity of the binarized image.</param>
        /// <returns>The binarized image</returns>
        public static Image<Gray, Byte> BinarizeImage(Image<Gray, Byte> inputImage, Gray maxintensity)
        {            
            IntPtr grayimage = inputImage.Ptr;
            IntPtr processed_image;
            Image<Gray, Byte> imagetemp = inputImage.CopyBlank();
            processed_image = imagetemp.Ptr;
            CvInvoke.cvThreshold(grayimage, processed_image, 160, maxintensity.Intensity, THRESH.CV_THRESH_BINARY | THRESH.CV_THRESH_OTSU);
            imagetemp.Ptr = processed_image;
            return imagetemp;
        }

        //private static Image<Gray, Byte> BinarizeImage(Image<Gray, Byte> inputImage)
        //{
        //    IntPtr resultPtr = __BinarizeImage(inputImage.Ptr);

        //    Image<Gray, Byte> result = new Image<Gray, Byte>(inputImage.Width, inputImage.Height);
        //    result.Ptr = resultPtr;

        //    return result;
        //}

        private static Image<Gray, Byte> ErodeImage(Image<Gray, Byte> inputImage)
        {
            IntPtr resultPtr = __ErodeImage(inputImage.Ptr);

            Image<Gray, Byte> result = new Image<Gray, Byte>(inputImage.Width, inputImage.Height);
            result.Ptr = resultPtr;

            return result;
        }

        public static void SobelFilter(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage)
        {
            __SobelFilter(inputImage.Ptr, outputImage.Ptr);
        }

        public static Image<Gray, Byte> Resize(Image<Gray, Byte> inputImage, double scale)
        {
            return inputImage.Resize(scale, INTER.CV_INTER_LINEAR);            
        }
        public static Image<Gray, Byte> Resize(Image<Gray, Byte> inputImage, int width, int height)
        {
            return inputImage.Resize(width, height, INTER.CV_INTER_LINEAR);
        }
        public static Image<Bgr, Byte> Resize(Image<Bgr, Byte> inputImage, double scale)
        {
            return inputImage.Resize(scale, INTER.CV_INTER_LINEAR);
        }
        public static Image<Bgr, Byte> Resize(Image<Bgr, Byte> inputImage, int width, int height)
        {
            return inputImage.Resize(width, height, INTER.CV_INTER_LINEAR);
        }
        //private static Image<Gray, Byte> ResizeWithRate(Image<Gray, Byte> inputImage, double rate)
        //{
        //    IntPtr resultPtr = __ResizeWithRate(inputImage.Ptr, rate);

        //    Image<Gray, Byte> result = new Image<Gray, Byte>(inputImage.Width, inputImage.Height);
        //    result.Ptr = resultPtr;

        //    return result;
        //}

        //private static IntPtr Resize(IntPtr inputImage)
        //{
        //    IntPtr resultPtr = __Resize(inputImage);
        //    return resultPtr;
        //}

        public static void EraseBackgroundWithThreshold1(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage, int Threshold)
        {
            __EraseBackgroundWithThreshold1(inputImage.Ptr, outputImage.Ptr, Threshold);
        }

        public static void EraseBackgroundWithThreshold2(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage, int backGray, int threshold)
        {
            __EraseBackgroundWithThreshold2(inputImage.Ptr, outputImage.Ptr, backGray, threshold);
        }

        public static void EraseBackground(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage)
        {
            __EraseBackground(inputImage.Ptr, outputImage.Ptr);
        }

        public static void RemoveGrid(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage, Image<Gray, Byte> gridImage)
        {
            __RemoveGrid(inputImage.Ptr, outputImage.Ptr, gridImage.Ptr);
        }

        public static void GetGrid(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage, double angle)
        {
            __GetGrid(inputImage.Ptr, outputImage.Ptr, angle);
        }

        public static void BlurGrid(Image<Gray, Byte> inputImage, Image<Gray, Byte> outputImage, Image<Gray, Byte> gridImage)
        {
            __BlurGrid(inputImage.Ptr, outputImage.Ptr, gridImage.Ptr);
        }
        #endregion
    }
}
